use std::any::Any;

use log::info;
use poker_lib::{PokerCards, Suit};
use tge::{context::Context, game::Model};

use spades_lib::{
    ai::{ai_bid, ai_play},
    player::Player,
    round::Round,
    score::RoundResult,
    table::Table,
    utils::Utils,
};

pub enum SpadesState {
    Dealing,
    Bidding,
    Playing,
    Billing,
}

impl From<u8> for SpadesState {
    fn from(orig: u8) -> Self {
        let cs;
        match orig {
            0 => cs = SpadesState::Dealing,
            1 => cs = SpadesState::Bidding,
            2 => cs = SpadesState::Playing,
            3 => cs = SpadesState::Billing,
            _ => cs = SpadesState::Playing,
        };
        cs
    }
}

#[derive(Debug)]
pub struct SpadesRoundData {
    pub piles: Vec<Vec<i16>>,
    pub bids: Vec<i16>,
    pub tricks: Vec<i16>,
    pub spades: Vec<u8>,
    pub bags: [i16; 4],
    pub scores: [i16; 4],
    pub data: RoundResult,
}
#[derive(Debug)]
pub struct SpadesMatchData {
    pub team_scores: [i16; 4],
    pub team_bags: [i16; 4],
    pub banker_ranks: [i16; 5],
    //每局的结果
    pub rounds: Vec<SpadesRoundData>,
    //获胜队伍id
    pub team_win_id: i16,
    pub sec_team_id: i16,
    pub third_team_id: i16,
    pub last_team_id: i16,
    // score delta between 1st and third teams
    pub score_fs: i16,
    // score delta between 1st and last teams
    pub score_fl: i16,
    //获胜队伍胜率
    pub team_win_percent: i8,
    //每个队员的达成率
    pub player_win_percent: [i8; 4],
    //每个队员叫0占比
    pub player_nil_percent: [i8; 4],
    //每个队员叫0次数
    pub player_nil_times: [i16; 4],
    //每个队员的得分总数
    pub player_scores: [i16; 4],
    //每个队员的spades平均值
    pub player_spades: [i8; 4],
    //每个队员的Ak数量
    pub player_ak: [i8; 4],
    pub mvp: usize,
    pub score_id: i32,
    pub group_id: String,
    pub cards: Vec<Vec<i16>>,
    pub bids: Vec<Vec<i16>>,
    pub tricks: Vec<Vec<i16>>,

    //1 波峰牌库 2 波谷牌库 3 牌库2 4 牌库1
    pub write_pool_type: u8,
    pub write_condition_type: u8,
}
// #[derive(Debug, Serialize)]
// pub struct SpadesMatchSaveData {
//     pub cards: Vec<i16>,
// }
pub struct SpadesSimModel {
    pub players: [Player; 4],
    pub round: Round,
    pub table: Table,
    pub match_data: SpadesMatchData,
}
impl SpadesSimModel {
    pub fn new(score_id: i32) -> Self {
        let ps: [Player; 4] = [
            Player::new("ME", 0),
            Player::new("P1", 1),
            Player::new("P2", 2),
            Player::new("P3", 3),
        ];
        Self {
            players: ps,
            round: Round::new(),
            table: Table::new(),
            match_data: SpadesMatchData {
                team_scores: [0, 0, 0, 0],
                team_bags: [0, 0, 0, 0],
                rounds: vec![],
                team_win_id: 0,
                team_win_percent: 0,
                player_win_percent: [0, 0, 0, 0],
                player_scores: [0, 0, 0, 0],
                player_nil_percent: [0, 0, 0, 0],
                player_spades: [0, 0, 0, 0],
                player_ak: [0, 0, 0, 0],
                player_nil_times: [0, 0, 0, 0],
                mvp: 0,
                score_id: score_id,
                cards: vec![],
                bids: vec![],
                tricks: vec![],
                sec_team_id: -1,
                third_team_id: -1,
                last_team_id: -1,
                score_fs: -1,
                score_fl: -1,
                group_id: String::new(),
                banker_ranks: [-1, -1, -1, -1, -1],
                write_pool_type: 0,
                write_condition_type:0
            },
        }
    }
    pub fn reset(&mut self, ctx: &mut Context) {
        ctx.rand.srand_now();
        self.round.reset(&mut ctx.rand);
        self.table.reset();
        ctx.state = SpadesState::Dealing as u8;
        self.timer_fire(0, ctx);
    }
    pub fn next_round(&mut self, ctx: &mut Context) {
        ctx.rand.srand_now();
        self.round.next_round();
        ctx.state = SpadesState::Dealing as u8;
        info!("state a new dealing -> dealing...");
        self.timer_fire(0, ctx);
    }

    pub fn dealing(&mut self, ctx: &mut Context) {
        ctx.rand.srand_now();
        self.round.deal(&mut ctx.rand, self.table.joker == 1);
        ctx.state = SpadesState::Bidding as u8;
        if self.table.frist_banker == -1 {
            self.table.frist_banker = self.round.banker;
        }
        self.timer_fire(0, ctx);
        info!("dealing ok, begin bidding...");
    }

    pub fn bidding(&mut self, ctx: &mut Context) {
        let tid = self.round.current_seat_id;
        let cseat = &mut self.round.seats[tid];
        // 如果手工输入，应用输入值，否则应用AI算法
        let bid = if cseat.bid != None {
            cseat.bid.unwrap()
        } else {
            ai_bid(tid, &mut self.table, &mut self.round)
        };
        info!("state bidding -> {:?}", bid);
        if self.round.bid(bid) {
            ctx.state = SpadesState::Playing as u8;
            self.timer_fire(0, ctx);
            info!("state bidding -> playing...");
        } else {
            self.timer_fire(0, ctx);
        }
    }
    pub fn playing(&mut self, ctx: &mut Context) {
        let tid = self.round.current_seat_id;
        let cseat = &mut self.round.seats[tid];
        // 如果手工输入，应用输入值，否则应用AI算法
        let out_card = if cseat.out_card != None {
            cseat.out_card.unwrap()
        } else {
            ai_play(tid, &mut self.table, &mut self.round)
        };
        if self.round.play(out_card) {
            // round 结算 会更新table的 game_state
            self.round.compute_round_result(&mut self.table);

            //检查是否对局结束
            if self.table.check_game_finish() {
                self.record_match_data(self.table.mode);
                return;
            }
            self.next_round(ctx);
        } else {
            self.timer_fire(0, ctx);
        }
    }
    pub fn record_match_data(&mut self, mode: i16) {
        let table = &self.table;
        let match_data = &mut self.match_data;
        let winner = table.winner_team_id;
        if winner == -1 {
            return;
        }
        for team in table.team_states.iter() {
            match_data.team_scores[team.id] = team.score;
        }
        match_data.team_win_id = winner;
        match_data.banker_ranks[4] = table.frist_banker as i16;
        match_data.sec_team_id = table.sec_team_id;
        match_data.third_team_id = table.third_team_id;
        match_data.last_team_id = table.last_team_id;
        match_data.score_fs = table.score_fs;
        match_data.score_fl = table.score_fl;

        let rounds = &table.rounds;
        //origin piles
        //记录队伍获胜次数
        let mut t_win_count: [u8; 4] = [0, 0, 0, 0];
        //记录队伍累计bag数
        let mut t_bag_total: [i16; 4] = [0, 0, 0, 0];
        //记录队伍每个round的平均bag数
        // let mut t_bag_avg: [i16; 2] = [0, 0];
        //记录玩家达成次数
        let mut p_win_count: [i16; 4] = [0, 0, 0, 0];
        let mut p_scores: [i16; 4] = [0, 0, 0, 0];
        let mut p_bags: [i16; 4] = [0, 0, 0, 0];
        let mut player_spades = [0, 0, 0, 0];
        let mut player_scores: [i16; 4] = [0, 0, 0, 0];
        let mut player_ak = [0, 0, 0, 0];
        let mut player_nil_times = [0, 0, 0, 0];
        let rnd_len = rounds.len();
        for round in rounds {
            let mut player_piles = vec![];
            let mut bids = vec![];
            let mut tricks = vec![];
            let mut spades = vec![];
            let mut bags = [0i16, 0, 0, 0];
            t_win_count[round.win_team_id as usize] += 1;
            for (i, team_score) in round.teams.iter().enumerate().take(4) {
                t_bag_total[i] += team_score.bags;
                bags[i] = team_score.bags;
            }
            let p_length = round.players.len();
            for (i, round_player) in round.players.iter().enumerate().take(p_length) {
                let mut pile = vec![];
                let mut cards = PokerCards::new();
                match cards.assign_by_cards(&round_player.pile) {
                    Ok(_) => {
                        for card in &cards.cards {
                            let card_v = card.to_spades_n();
                            pile.push(card_v)
                        }
                    }
                    Err(_) => {}
                }
                player_piles.push(pile);
                bids.push(round_player.bid);
                tricks.push(round_player.tricks);
                spades.push(cards[Suit::Spade].n);

                //计算是否达成
                if round_player.bid == 0 {
                    if round_player.tricks == 0 {
                        p_win_count[i] += 1;
                        player_nil_times[i] += 1;
                    }
                } else if round_player.bid <= round_player.tricks {
                    p_win_count[i] += 1;
                }

                //计算AK数量
                player_ak[i] += Utils::get_ak_num(&cards.cards);
                //累计黑桃牌数量
                player_spades[i] += spades[i];
                //累计得分
                p_scores[i] += round_player.score;
                //单局得分
                player_scores[i] = round_player.score;
                //累计bag数
                p_bags[i] += round_player.bags;
            }
            let round_data = SpadesRoundData {
                piles: player_piles,
                bids: bids,
                tricks: tricks,
                spades: spades,
                bags: bags,
                scores: player_scores,
                data: round.clone(),
            };
            match_data.rounds.push(round_data);
            // println!("round_result: {:?}", round);
            // println!("________________________________________________________________");
        }
        //
        match_data.team_bags = t_bag_total;
        //队伍的胜率
        let percentage = t_win_count[winner as usize] as f32 / rnd_len as f32;
        match_data.team_win_percent = (percentage * 100.0).round() as i8;
        let mut max_score = 0;
        let mut mvp = 0;
        for i in 0..4 {
            //个人平均AK数
            match_data.player_ak[i] = (player_ak[i] as f32 / rnd_len as f32).ceil() as i8;
            //个人平均黑桃数
            match_data.player_spades[i] = (player_spades[i] as f32 / rnd_len as f32).ceil() as i8;
            //达成百分比
            let mut percentage = p_win_count[i] as f32 / rnd_len as f32;
            match_data.player_win_percent[i] = (percentage * 100.0).round() as i8;
            // 叫0达成百分比
            percentage = player_nil_times[i] as f32 / rnd_len as f32;
            match_data.player_nil_percent[i] = (percentage * 100.0).round() as i8;
            //叫0 达成次数
            match_data.player_nil_times = player_nil_times;
            //累计得分
            let p_finanl_score = p_scores[i]
                - (p_bags[i] as f32 / self.table.limit_bag as f32).ceil() as i16
                    * self.table.score_bag_penalty;
            match_data.player_scores[i] = p_finanl_score;
            if p_finanl_score > max_score {
                mvp = i;
                max_score = p_finanl_score;
            } else {
                //相同分数的情况 mvp取获胜队伍里队员id
                if p_finanl_score == max_score {
                    if winner == 0 {
                        if i == 0 || i == 2 {
                            mvp = i;
                            max_score = p_finanl_score;
                        }
                    } else {
                        if i == 1 || i == 3 {
                            mvp = i;
                            max_score = p_finanl_score;
                        }
                    }
                }
            }
        }
        //计算排名
        let u_win_id = winner as usize;
        for player_id in 0..4 {
            if mode == 1 {
                let team_id = Utils::get_team_by_player_id(player_id, mode);
                let partner_id = Utils::get_partner_player_id(player_id);
                let match_scores = match_data.player_scores;
                let score_delta = match_scores[player_id] - match_scores[partner_id];
                if team_id == u_win_id {
                    if score_delta >= 0 {
                        match_data.banker_ranks[player_id] = 1;
                        match_data.banker_ranks[partner_id] = 3;
                    } else {
                        match_data.banker_ranks[player_id] = 3;
                        match_data.banker_ranks[partner_id] = 1;
                    }
                } else {
                    if score_delta >= 0 {
                        match_data.banker_ranks[player_id] = 2;
                        match_data.banker_ranks[partner_id] = 4;
                    } else {
                        match_data.banker_ranks[player_id] = 4;
                        match_data.banker_ranks[partner_id] = 2;
                    }
                }
            } else if mode == 2 {
                let pid = player_id as i16;
                match pid {
                    id if id == match_data.team_win_id => {
                        match_data.banker_ranks[player_id] = 1;
                    }
                    id if id == match_data.sec_team_id => {
                        match_data.banker_ranks[player_id] = 2;
                    }
                    id if id == match_data.third_team_id => {
                        match_data.banker_ranks[player_id] = 3;
                    }
                    id if id == match_data.last_team_id => {
                        match_data.banker_ranks[player_id] = 4;
                    }
                    _ => {}
                }
            }
        }
        match_data.mvp = mvp;
    }
    pub fn timer_fire(&mut self, _time: i32, ctx: &mut Context) {
        let state = SpadesState::from(ctx.state);
        match state {
            SpadesState::Dealing => self.dealing(ctx),
            SpadesState::Bidding => self.bidding(ctx),
            SpadesState::Playing => self.playing(ctx),
            SpadesState::Billing => self.dealing(ctx),
        }
    }
}

impl Model for SpadesSimModel {
    fn init(&mut self, ctx: &mut Context) {
        self.reset(ctx);
    }
    fn handle_timer(&mut self, _ctx: &mut Context, _dt: f32) {}

    fn handle_auto(&mut self, _ctx: &mut Context, _dt: f32) {}
    fn handle_event(&mut self, _ctx: &mut Context, _dt: f32) {}
    fn as_any(&mut self) -> &mut dyn Any {
        self
    }

    fn handle_input(&mut self, _ctx: &mut Context, _dt: f32) {}
}
